import { defineComponent, reactive, onBeforeUnmount, provide, inject, getCurrentInstance } from 'vue';

interface AppRoute {
  path?: string,
  hash?: string,
  param?: string
}

function getRoute(): AppRoute | null {
  let locationHash = window.location.hash;
  if (!locationHash) return null;

  if (locationHash.charAt(0) === '#') {
    locationHash = locationHash.slice(1);
  }

  if (!locationHash) return null;

  const [path, hash] = (decodeURIComponent(locationHash)).split('#');

  return {
    path,
    hash
  }
}

const APP_NAVIGATOR_PROVIDER = '@@APP_NAVIGATOR_PROVIDER';

function useAppNavigator(props: {defaultPath?: string}) {

  const ctx = getCurrentInstance();

  let initRoute = getRoute();
  if (!initRoute) {
    initRoute = {
      path: props.defaultPath
    }
  }

  const state = reactive({
    route: initRoute
  });

  const utils = {
    reset: () => {
      const route = getRoute();
      if (!!route) {
        state.route = route;
      }
    }
  }
  const handler = {
    hashChange: () => utils.reset()
  }

  const methods = {
    go: (path: string) => {
      window.location.hash = encodeURIComponent(path);
    }
  };

  window.addEventListener('hashchange', handler.hashChange);
  onBeforeUnmount(() => window.removeEventListener('hashchange', handler.hashChange));

  const refer = {
    state,
    methods
  };

  (ctx as any)._refer = refer;

  provide(APP_NAVIGATOR_PROVIDER, refer);
  return refer;
}

export function injectAppNavigator (): ReturnType<typeof useAppNavigator> {

  return inject(APP_NAVIGATOR_PROVIDER) as any;
}
export const AppNavigator = defineComponent({
  props: {
    defaultPath: String,
  },
  setup(props, { slots }) {
    useAppNavigator(props);
    return slots.default || null;
  }
});